home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
076-100
/
disk_098
/
hddriver
/
driver
/
lib.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-06
|
7KB
|
286 lines
/*
* Copyright 1987 Alan Kent
*
* Permission is granted to redistribute this code as long
* as this message is retained in the code and the code is
* not sold without written permission from the author.
*
* UUCP: {seismo,hplabs,mcvax,ukc,nttlab}!munnari!goanna.oz!ajk
* ACSnet: ajk@goanna.oz
* ARPA: munnari!goanna.oz!ajk@SEISMO.ARPA
*/
#include "hd.h"
/* initialize library node */
LONG
cLibInit ( dev , seg_list )
struct hd_dev *dev;
BPTR seg_list; /* I think its BPTR */
{
int i;
struct hd_unit *unit;
struct Process *process;
/* easier here than trying to use the automatic initalization */
dev->hd_Dev.dd_Library.lib_Node.ln_Type = NT_DEVICE;
dev->hd_Dev.dd_Library.lib_Node.ln_Name = dev_name;
dev->hd_Dev.dd_Library.lib_Flags = LIBF_SUMUSED|LIBF_CHANGED;
dev->hd_Dev.dd_Library.lib_Version = HD_VERSION;
dev->hd_Dev.dd_Library.lib_Revision = HD_REVISION;
dev->hd_Dev.dd_Library.lib_IdString = (APTR)dev_id_string;
/* Initiate controller. Actually, this is being a bit naughty. */
/* The signals should be allocated in the created subtask, but */
/* I know the subtask does not allocate any signals itself so */
/* any signal we create will be ok. The signal is created for */
/* the interrupt driven controller */
if ( wd_open () < 0 )
return ( NULL );
/* create a single global port on which ALL messages for all devices */
/* and units will arrive. Note that CreatePort allocates a signal. */
/* See the above discussion about signals and wd_open() */
port = CreatePort ( (char*)NULL , (LONG)0 );
if ( port == NULL ) {
wd_close ();
return ( NULL );
}
/* initiate cache */
if ( init_cache () < 0 ) {
wd_close ();
DeletePort ( port );
return ( NULL );
}
/* Create a single task to be shared by all units. */
/* This is to ensure exclusive access to the controller. */
/* Note that the caching at present will only work with a */
/* single unit */
process = CreateProc ( dev_name ,
(LONG)HD_PRIORITY ,
(LONG)proc_seg_list >> 2L ,
(LONG)HD_STACKSIZE );
if ( process == NULL ) {
free_cache ();
wd_close ();
DeletePort ( port );
return ( NULL );
}
/* actually, CreateProc returns a pointer to the message port */
/* to use with C, must adjust to start of procedure */
process = PROCPTR ( process );
/* ok, now anything to do with controller is for subtask. */
/* When wd_open was called, it initialized the interrupts to */
/* send an interrupt to this task. Now interrupts should be */
/* sent to the subprocess. */
wd_subtask ( &process->pr_Task );
/* similarly, the port should send message port signals to the task */
port->mp_SigTask = &process->pr_Task;
/* initialize all units */
for ( i = 0; i < HD_NUMUNITS; i++ ) {
unit = &dev->hd_Unit[i];
unit->hdu_Unit.unit_OpenCnt = 0;
unit->hdu_Unit.unit_MsgPort = port;
unit->hdu_UnitNum = i;
unit->hdu_Task = &process->pr_Task; /* shared */
}
return ( (LONG)dev );
}
/* actually, cOpen does not need to return anything, but libraries do, */
/* so I am returning the device pointer just to be safe */
struct hd_dev *
cOpen ( dev , ior , unit_num , flags )
struct hd_dev *dev;
struct IOExtHD *ior;
LONG unit_num;
ULONG flags;
{
register struct hd_unit *unit;
ior->iohd_TD.iotd_Req.io_Error = 0;
/* check for legal unit number */
if ( unit_num < 0 || unit_num >= HD_NUMUNITS ) {
ior->iohd_TD.iotd_Req.io_Error = TDERR_BadUnitNum;
return ( NULL );
}
unit = &dev->hd_Unit[ unit_num ];
/* set up request, unit, open counts, and we no longer want to expunge */
/* the library when all closes are done */
ior->iohd_TD.iotd_Req.io_Unit = &unit->hdu_Unit;
dev->hd_Flags &= ~ (ULONG) LIBF_DELEXP;
dev->hd_Dev.dd_Library.lib_OpenCnt++;
unit->hdu_Unit.unit_OpenCnt++;
return ( dev );
}
BPTR /* seg list */
cClose ( dev , ior )
struct hd_dev *dev;
struct IOExtHD *ior;
{
ior->iohd_TD.iotd_Req.io_Error = 0;
if ( --(ior->iohd_TD.iotd_Req.io_Unit->unit_OpenCnt) == 0 ) {
/* expunge unit */
/* well, actually we have only one task for all units so dont */
/* kill the unit task */
}
/* clear out ior so that it cant be accidently reused */
ior->iohd_TD.iotd_Req.io_Unit = NULL;
ior->iohd_TD.iotd_Req.io_Device = NULL;
/* one less person using the device driver */
if ( --(dev->hd_Dev.dd_Library.lib_OpenCnt) <= 0
&& ( dev->hd_Flags & LIBF_DELEXP ) )
/* no one has us open anymore and we have a delayed expunge */
/* command pending, so do it! */
return ( cExpunge ( dev ) );
return ( NULL );
}
BPTR /* seg list */
cExpunge ( dev )
struct hd_dev *dev;
{
BPTR seg_list;
if ( dev->hd_Dev.dd_Library.lib_OpenCnt > 0 ) {
/* someone still has the library open - mark that should be */
/* deleted when everyone has closed us */
dev->hd_Flags |= LIBF_DELEXP;
return ( NULL );
}
/* stop anyone else from opening the device */
Remove ( dev );
free_cache ();
wd_close ();
DeletePort ( port );
CloseLibrary ( DOSBase );
seg_list = dev->hd_SegList;
FreeMem ( ((char *)dev) - dev->hd_Dev.dd_Library.lib_NegSize ,
(LONG) dev->hd_Dev.dd_Library.lib_NegSize
+ (LONG) dev->hd_Dev.dd_Library.lib_PosSize );
return ( seg_list );
}
void
cBeginIO ( dev , ior )
struct hd_dev *dev;
struct IOExtHD *ior;
{
ior->iohd_TD.iotd_Req.io_Error = 0;
/* If some commands can be done very quickly, then a call to */
/* perform_io () could be made. Care must be taken to ensure */
/* that the disk driver task is not in perform_io () at the */
/* same time so some global lock variable should be used. */
/* Also, if the device has been stopped with CMD_STOP, we should */
/* not try to do the command immediately. When the command cannot */
/* be done immediately, the requests must be queued by sending */
/* them to the task. For safty, Disable() and Enable() may need to */
/* be called to safely examine and modify global variables. */
/* In the device driver, the status commands must always work */
/* immediately and cannot do a Wait() as they are called from */
/* interrupts too (and so use the interrupt stack). (Well, thats */
/* what the manual said anyway). Since for a harddisk the code */
/* is so trivial, it was repeated here rather than calling */
/* perform_io(). */
if ( ( ior->iohd_TD.iotd_Req.io_Command & ~(ULONG)TDF_EXTCOM ) > HD_LASTCOMM ) {
ior->iohd_TD.iotd_Req.io_Error = IOERR_NOCMD;
return;
}
switch ( (int) ior->iohd_TD.iotd_Req.io_Command ) {
case TD_CHANGENUM :
ior->iohd_TD.iotd_Req.io_Actual = CHANGE_COUNT;
break;
case TD_CHANGESTATE :
ior->iohd_TD.iotd_Req.io_Actual = 0;
break;
case TD_PROTSTATUS :
ior->iohd_TD.iotd_Req.io_Actual = 0;
break;
default :
/* clear quick flag to say that message is going to be queued */
ior->iohd_TD.iotd_Req.io_Flags &= ~ (ULONG) IOF_QUICK;
PutMsg ( ior->iohd_TD.iotd_Req.io_Unit->unit_MsgPort , ior );
break;
}
}
void
cAbortIO ( dev , ior )
struct hd_dev *dev;
struct IOExtHD *ior;
{
ior->iohd_TD.iotd_Req.io_Error = 0;
/* can any of the commands be aborted? */
}